package com.itany.corejava.code08_常用类.object;

/**
 * @author 石小俊
 * @version 1.0
 * @date 2023年03月14日 13:45
 */
public class Test01_常用方法 {
    public static void main(String[] args) throws CloneNotSupportedException {
//        getClassTest();
//        equalsTest();
//        hashCodeTest();
//        toStringTest();
//        cloneTest();
//        cloneTest2();
        finalizeTest();
    }

    public static void getClassTest(){
        Person person = new Person();
        System.out.println(person);
        // 所有的类都继承Object类,因此可以调用Object中的方法
        // getClass方法的返回值是一个class对象,表示的是运行时对象
        // 格式:class 包名.类名
        Class c = person.getClass();
        System.out.println(c);

        // 此时属于多态,子类的对象指向了父类的引用
        // person2编译时类型为:Person
        // person2运行时类型为:Student
        Person person2 = new Student();
        Class c2 = person2.getClass();
        System.out.println(c2);

        // 此时想要调用子类中的方法,必须将类型转换为子类对象
        // 即:向下转型,此时最好通过instanceof进行判断
        if(person2 instanceof Student){
            Student student = (Student) person2;
            student.show();
            // ((Student) person2).show();
        }

        // 也可以通过运行时类型进行判断
        System.out.println(person2.getClass());
        // 每一个类都有一个class属性
        // 用于判断当前类运行时所对应的class类型
        System.out.println(Person.class);
        System.out.println(Student.class);
        // 当当前对象的运行时类型与需要强转的类的类型一致时,可以强转
        if(person2.getClass() == Student.class){
            ((Student) person2).show();
        }
    }

    public static void equalsTest(){
        String s1 = new String("admin");
        String s2 = new String("admin");
        // 在通过==进行比较的时候,如果变量地址不一致,也会返回false
        System.out.println(s1 == s2); // false
        // 字符串重写了Object的equals方法,用于直接比较值,忽略地址
        System.out.println(s1.equals(s2)); // true

        Person person = new Person("admin",20);
        Person person2 = new Person("admin",20);
        System.out.println(person == person2); // false
//        System.out.println(person.equals(person2)); // false
        // 当重写了equals方法之后,根据方法的规则进行比较
        // 此处比较的是对象的name与age是否相等
        System.out.println(person.equals(person2)); // true
    }

    public static void hashCodeTest(){
        Person person = new Person("admin",20);
        Person person2 = new Person("jack",18);
        System.out.println(person.hashCode());
        System.out.println(person2.hashCode());
    }

    public static void toStringTest(){
        Person person = new Person("admin",20);
        System.out.println(person);
    }

    public static void cloneTest() throws CloneNotSupportedException {
        Person person = new Person("admin",18);
        System.out.println(person);

        // 调用clone方法报错,查看源码发现该方法被protected修饰
        // 只有当前类、同一个包、子类可以调用
        // 因此,在Person重写方法后可以访问
        Person person2 = (Person) person.clone();
        // 此时报错,CloneNotSupportedException
        // 重写clone方法,必须实现Cloneable接口
        // 实现接口后成功
        System.out.println(person2);
    }

    public static void cloneTest2() throws CloneNotSupportedException {
        Address address = new Address("江苏","南京");
        Person person = new Person("admin",18,address);
        System.out.println(person);

        Person person2 = (Person) person.clone();
        System.out.println(person2);
        System.out.println("***************开始修改***************");
        // 克隆之后修改数据
        // 修改name对person没有影响
        person2.setName("jack");
        // 修改address中的属性时,person也随之改变
        person2.getAddress().setCity("苏州");
        System.out.println(person);
        System.out.println(person2);

    }

    public static void finalizeTest(){
        Person person = new Person();
        Person person2 = person;
        person = null;
        person2 = null;
        // System.gc();
        Runtime.getRuntime().gc();
    }

}
